﻿#include <Windows.h>

unsigned int dword_10003338[256];
int CRC32(LPCSTR lpFileName)
{
	int v1; // ebx@1
	const CHAR* v2; // edi@1
	unsigned int v3; // esi@1
	unsigned int v4; // ecx@2
	unsigned int v5; // edx@4
	unsigned int v6; // ecx@6
	unsigned int v7; // edx@8
	unsigned int v8; // ecx@10
	unsigned int v9; // edx@12
	unsigned int v10; // ecx@14
	char v11; // dl@16
	unsigned int v12; // ecx@16
	unsigned int v13; // eax@16
	HANDLE v14; // edi@19
	DWORD v15; // esi@20
	HANDLE v16; // eax@22
	LPVOID v17; // eax@24
	unsigned int v18; // ebx@25
	char* v19; // edx@25
	unsigned __int8 v20; // al@26
	HANDLE hObject; // [sp+Ch] [bp-10h]@22
	LPVOID v23; // [sp+10h] [bp-Ch]@24
	DWORD FileSizeHigh; // [sp+14h] [bp-8h]@16

	v1 = 0;
	v2 = lpFileName;
	v3 = 0;
	do
	{
		v4 = (v3 >> 1) ^ 0xEDB88320;
		if (!(v3 & 1))
			v4 = v3 >> 1;
		v5 = (v4 >> 1) ^ 0xEDB88320;
		if (!(v4 & 1))
			v5 = v4 >> 1;
		v6 = (v5 >> 1) ^ 0xEDB88320;
		if (!(v5 & 1))
			v6 = v5 >> 1;
		v7 = (v6 >> 1) ^ 0xEDB88320;
		if (!(v6 & 1))
			v7 = v6 >> 1;
		v8 = (v7 >> 1) ^ 0xEDB88320;
		if (!(v7 & 1))
			v8 = v7 >> 1;
		v9 = (v8 >> 1) ^ 0xEDB88320;
		if (!(v8 & 1))
			v9 = v8 >> 1;
		v10 = (v9 >> 1) ^ 0xEDB88320;
		if (!(v9 & 1))
			v10 = v9 >> 1;
		FileSizeHigh = v10;
		v11 = v10;
		v12 = v10 >> 1;
		v13 = v12 ^ 0xEDB88320;
		if (!(v11 & 1))
			v13 = v12;
		dword_10003338[v3++] = v13;
	} while ((signed int)v3 <= 255);
	v14 = CreateFileA(v2, 0x80000000, 1u, 0, 3u, 0x80u, 0);
	if (v14 != (HANDLE)-1)
	{
		FileSizeHigh = 0;
		v15 = GetFileSize(v14, &FileSizeHigh);
		if (v15 != -1 && !FileSizeHigh)
		{
			v16 = CreateFileMappingA(v14, 0, 2u, 0, 0, 0);
			hObject = v16;
			if (v16 != (HANDLE)-1)
			{
				if (v16)
				{
					v17 = MapViewOfFile(v16, 4u, 0, 0, 0);
					v23 = v17;
					if (v17)
					{
						v18 = -1;
						v19 = (char*)v17;
						if (v15)
						{
							do
							{
								v20 = *v19++;
								v18 = dword_10003338[(unsigned __int8)v18 ^ v20] ^ (v18 >> 8);
								--v15;
							} while (v15);
							v17 = v23;
						}
						v1 = ~v18;
						UnmapViewOfFile(v17);
						CloseHandle(hObject);
					}
				}
			}
		}
		CloseHandle(v14);
	}
	return v1;
}

BOOL WinTrustHooked = FALSE;
void HookWinTrust() {
	DWORD flOldProtect = 0;
	HMODULE m = LoadLibraryW(L"wintrust.dll");
	if (m) {
		auto p1 = GetProcAddress(m, "WinVerifyTrust");
		if (p1) {
			VirtualProtect(p1, 5, PAGE_EXECUTE_READWRITE, &flOldProtect);
			(*(DWORD*)p1) = 214089779;
			*((BYTE*)p1 + 4) = 0;
			VirtualProtect(p1, 0xFFFFFFFF, flOldProtect, &flOldProtect);
		}
		auto p2 = GetProcAddress(m, "WinVerifyTrustEx");
		if (p2) {
			VirtualProtect(p2, 5, PAGE_EXECUTE_READWRITE, &flOldProtect);
			(*(DWORD*)p2) = 214089779;
			*((BYTE*)p2 + 4) = 0;
			VirtualProtect(p2, 0xFFFFFFFF, flOldProtect, &flOldProtect);
		}
		WinTrustHooked = TRUE;
	}
}

#define SHFOLDERAPI           EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE

typedef HRESULT(STDAPICALLTYPE* __SHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
typedef HRESULT(STDAPICALLTYPE* __SHGetFolderPathW)(HWND, int, HANDLE, DWORD, LPWSTR);
__SHGetFolderPathA _SHGetFolderPathA;
__SHGetFolderPathW _SHGetFolderPathW;

char* PatchOffset = 0;
int (*FinalizeArrayOffset)(void);
__declspec(naked) int patchFunc()
{
	//__asm {
	//	push eax
	//	mov eax, [PatchOffset]
	//	cmp eax, [esp + 4]
	//	jne done
	//	mov eax, [ebp + 2Ch]
	//	mov byte ptr[eax], 1
	//done:
	//	pop eax
	//	jmp dword ptr[FinalizeArrayOffset]
	//}
	__asm {
		push eax
		mov eax, [PatchOffset]
		cmp eax, [esp + 4]//判断当前是否是要补丁的位置
		jne done
		mov eax, [ebp + 2Ch]
		mov byte ptr[eax], 1
		done:
		pop eax
			jmp dword ptr[FinalizeArrayOffset]
	}
}

HMODULE hGlobalModule = NULL;

//#define TEST

#if defined(TEST)
#define BDSCrc32  116066644
#define BDSPatchOffset 130006
#define BDSFinalizeArrayOffset 1035924
#define LicenseManagerCrc32 2186776113
#define LicenseManagerPatchOffset 1354078
#define LicenseManagerFinalizeArrayOffset 4962128
#else
unsigned int BDSCrc32 = 116066644;
unsigned int BDSPatchOffset = 130006;
unsigned int BDSFinalizeArrayOffset = 1035924;
unsigned int LicenseManagerCrc32 = 2186776113;
unsigned int LicenseManagerPatchOffset = 1354078;
unsigned int LicenseManagerFinalizeArrayOffset = 4962128;

void ReadConfig() {
	char fileName[MAX_PATH];
	getcwd(fileName, sizeof(fileName));
	lstrcatA(fileName, "\\SHFolder.ini");

	DWORD dwAttrib = GetFileAttributesA(fileName);
	if (!(INVALID_FILE_ATTRIBUTES != dwAttrib && 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))) // 文件不存在
		return;

	BDSCrc32 = GetPrivateProfileIntA("Patch", "BDSCrc32", 116066644, fileName);
	BDSPatchOffset = GetPrivateProfileIntA("Patch", "BDSPatchOffset", 130006, fileName);
	BDSFinalizeArrayOffset = GetPrivateProfileIntA("Patch", "BDSFinalizeArrayOffset", 1035924, fileName);

	LicenseManagerCrc32 = GetPrivateProfileIntA("Patch", "LicenseManagerCrc32", 2186776113, fileName);
	LicenseManagerPatchOffset = GetPrivateProfileIntA("Patch", "LicenseManagerPatchOffset", 1354078, fileName);
	LicenseManagerFinalizeArrayOffset = GetPrivateProfileIntA("Patch", "LicenseManagerFinalizeArrayOffset", 4962128, fileName);
}
#endif

BOOL APIENTRY DllMain(HMODULE hModule,
	DWORD  ul_reason_for_call,
	LPVOID lpReserved
)
{
	CHAR Buffer[0x104];
	CHAR FileName[MAX_PATH];
	CHAR ConfigFileName[MAX_PATH];
	CHAR* Name;
	const CHAR* v6;
	HMODULE moudle, cMoudle;
	DWORD po = 0, fao = 0;
	char* v9, v10;
	DWORD flOldProtect = 0;
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		hGlobalModule = hModule;
		DisableThreadLibraryCalls(hModule);
		GetSystemDirectoryA(Buffer, 0x104);
		lstrcatA(Buffer, "\\SHFolder.dll");
		moudle = LoadLibraryA(Buffer);
		hModule = moudle;
		if (!moudle)
			return 1;
		_SHGetFolderPathA = (__SHGetFolderPathA)GetProcAddress(moudle, "SHGetFolderPathA");
		_SHGetFolderPathW = (__SHGetFolderPathW)GetProcAddress(moudle, "SHGetFolderPathW");
		cMoudle = GetModuleHandleW(NULL);
		GetModuleFileNameA(cMoudle, FileName, MAX_PATH);


#if defined(TEST)	
#else
		ReadConfig();
#endif

		Name = FileName;
		if (Name) {
			do
				++Name;
			while (*Name);
		}
		do
			--Name;
		while (*Name != 92);
		v6 = Name + 1;
		if (lstrcmpiA(v6, "bds.exe")) {
			if (!lstrcmpiA(v6, "LicenseManager.exe") && CRC32(FileName) == LicenseManagerCrc32) { // LicenseManager.exe
				po = (char*)cMoudle + LicenseManagerPatchOffset;
				fao = LicenseManagerFinalizeArrayOffset;
			}
		}
		else { // bds.exe
			if (CRC32(FileName) == BDSCrc32) {
				po = (char*)cMoudle + BDSPatchOffset;
				fao = BDSFinalizeArrayOffset;
			}
		}
		if (po != 0) {
			v9 = (char*)cMoudle + fao;
			PatchOffset = po;
			FinalizeArrayOffset = *(int (**)(void))v9;
			VirtualProtect((LPVOID)v9, 4, PAGE_EXECUTE_READWRITE, &flOldProtect);
			*(DWORD*)v9 = patchFunc;
			VirtualProtect((LPVOID)v9, 4, flOldProtect, &flOldProtect);
		}
		else {
			HookWinTrust();
		}
		break;
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
		if (!WinTrustHooked)
			HookWinTrust();
		break;
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

SHFOLDERAPI SHGetFolderPathA(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath) {
	return _SHGetFolderPathA(hwnd, csidl, hToken, dwFlags, pszPath);
}

SHFOLDERAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath) {
	return _SHGetFolderPathW(hwnd, csidl, hToken, dwFlags, pszPath);
}